﻿using AutoMapper;
using PMS.Core.Infrastructure.Mapper;
using PMS.Data.Entities.Customers;
using PMS.Data.Entities.SystemModules;
using PMS.Data.Entities.ScheduleTasks;
using PMS.Web.Framework.Models;
using PMS.Web.Models.Customers;
using PMS.Web.Models.SystemModules;
using PMS.Web.Models.ScheduleTasks;
using PMS.Data.Entities.Messages;
using PMS.Web.Models.Messages;
using PMS.Data.Entities.Stores;
using PMS.Services.Plugins;
using PMS.Data.Entities.Security;
using PMS.Data.Entities.NaviMenus;
using PMS.Web.Models.NaviMenus;

namespace PMS.Web.Models
{
    public class AutoMapperConfigurationProfile : Profile, IOrderedMapperProfile
    {
        #region Ctor
        public AutoMapperConfigurationProfile()
        {
            CreateCustomersMaps();
            CreateSystemModuleMaps();
            CreateSystemScheduleTaskMaps();
            CreateQueuedEmailMaps();
            CreateNaviMenuMaps();
            //add some generic mapping rules
            ForAllMaps((mapConfiguration, map) =>
            {
                //exclude Form and CustomProperties from mapping BaseEntityModel
                if (typeof(BaseEntityModel).IsAssignableFrom(mapConfiguration.DestinationType))
                {
                    map.ForMember(nameof(BaseEntityModel.HashId), options => options.Ignore());
                    map.ForMember(nameof(BaseEntityModel.CustomProperties), options => options.Ignore());
                }
                if(typeof(BaseSearchModel).IsAssignableFrom(mapConfiguration.DestinationType))
                {
                    map.ForMember(nameof(BaseSearchModel.Page), options => options.Ignore());
                    map.ForMember(nameof(BaseSearchModel.PageSize), options => options.Ignore());
                    map.ForMember(nameof(BaseSearchModel.AvailablePageSizes), options => options.Ignore());
                }

                //exclude ActiveStoreScopeConfiguration from mapping ISettingsModel
                if (typeof(ISettingsModel).IsAssignableFrom(mapConfiguration.DestinationType))
                    map.ForMember(nameof(ISettingsModel.ActiveStoreScopeConfiguration), options => options.Ignore());

                //exclude some properties from mapping store mapping supported entities and models
                if (typeof(IStoreMappingSupported).IsAssignableFrom(mapConfiguration.DestinationType))
                    map.ForMember(nameof(IStoreMappingSupported.LimitedToStores), options => options.Ignore());
                if (typeof(IStoreMappingSupportedModel).IsAssignableFrom(mapConfiguration.DestinationType))
                {
                    map.ForMember(nameof(IStoreMappingSupportedModel.AvailableStores), options => options.Ignore());
                    map.ForMember(nameof(IStoreMappingSupportedModel.SelectedStoreIds), options => options.Ignore());
                }

                //exclude some properties from mapping ACL supported entities and models
                if (typeof(IAclSupported).IsAssignableFrom(mapConfiguration.DestinationType))
                    map.ForMember(nameof(IAclSupported.SubjectToAcl), options => options.Ignore());
                if (typeof(IAclSupportedModel).IsAssignableFrom(mapConfiguration.DestinationType))
                {
                    map.ForMember(nameof(IAclSupportedModel.AvailableCustomerRoles), options => options.Ignore());
                    map.ForMember(nameof(IAclSupportedModel.SelectedCustomerRoleIds), options => options.Ignore());
                }

                ////exclude some properties from mapping discount supported entities and models
                //if (typeof(IDiscountSupportedModel).IsAssignableFrom(mapConfiguration.DestinationType))
                //{
                //    map.ForMember(nameof(IDiscountSupportedModel.AvailableDiscounts), options => options.Ignore());
                //    map.ForMember(nameof(IDiscountSupportedModel.SelectedDiscountIds), options => options.Ignore());
                //}

                if (typeof(IPluginModel).IsAssignableFrom(mapConfiguration.DestinationType))
                {
                    //exclude some properties from mapping plugin models
                    map.ForMember(nameof(IPluginModel.ConfigurationUrl), options => options.Ignore());
                    map.ForMember(nameof(IPluginModel.IsActive), options => options.Ignore());
                    map.ForMember(nameof(IPluginModel.LogoUrl), options => options.Ignore());

                    //define specific rules for mapping plugin models
                    if (typeof(IPlugin).IsAssignableFrom(mapConfiguration.SourceType))
                    {
                        map.ForMember(nameof(IPluginModel.DisplayOrder), options => options.MapFrom(plugin => ((IPlugin)plugin).PluginDescriptor.DisplayOrder));
                        map.ForMember(nameof(IPluginModel.FriendlyName), options => options.MapFrom(plugin => ((IPlugin)plugin).PluginDescriptor.FriendlyName));
                        map.ForMember(nameof(IPluginModel.SystemName), options => options.MapFrom(plugin => ((IPlugin)plugin).PluginDescriptor.SystemName));
                    }
                }

            });

        }
        #endregion

        #region Utilities
        /// <summary>
        /// Create customers maps 
        /// </summary>
        protected virtual void CreateCustomersMaps()
        {
            CreateMap<Organize, OrganizeTreeModel>()
                .ForMember(model => model.Title, options => options.Ignore())
                .ForMember(model => model.Field, options => options.Ignore())
                .ForMember(model => model.Href, options => options.Ignore())
                .ForMember(model => model.Spread, options => options.Ignore())
                .ForMember(model => model.Checked, options => options.Ignore())
                .ForMember(model => model.Disabled, options => options.Ignore());
            CreateMap<OrganizeTreeModel, Organize>()
                .ForMember(entity => entity.DataType, options => options.Ignore())
                .ForMember(entity => entity.CreatedOnTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.UpdatedOnTimeUtc, options => options.Ignore());

            //CustomerRole MapTo AdminRoleModel For WebApiCall
            //No Model To Entity Reverse Map
            CreateMap<CustomerRole, AdminRoleModel>()
                .ForMember(model => model.IsAdmin, options => options.Ignore());

            CreateMap<Customer, CustomerModel>()
               .ForMember(model => model.Password, options => options.Ignore())
               .ForMember(model => model.PasswordStrongLevel, options => options.Ignore())
               .ForMember(model => model.Gender, options => options.Ignore())
               .ForMember(model => model.DateOfBirth, options => options.Ignore())
               .ForMember(model => model.DefaultAddress, options => options.Ignore())
               .ForMember(model => model.DefaultAddressDetail, options => options.Ignore())
               .ForMember(model => model.RegisteredInStore, options => options.Ignore())
               .ForMember(model => model.CreatedOnTime, options => options.Ignore())
               .ForMember(model => model.LastActivityTime, options => options.Ignore())
               .ForMember(model => model.LastVisitedPage, options => options.Ignore())
               .ForMember(model => model.CustomerRoleNames, options => options.Ignore())
               .ForMember(model => model.AvatarImage, options => options.Ignore())
               //.ForMember(model => model.AvailableCustomerRoles, options => options.Ignore())
               //.ForMember(model => model.SelectedCustomerRoleIds, options => options.Ignore())
               .ForMember(model => model.SendEmail, options => options.Ignore())
               .ForMember(model => model.SendPm, options => options.Ignore())
               .ForMember(model => model.AllowSendingOfPrivateMessage, options => options.Ignore())
               .ForMember(model => model.AllowSendingOfWelcomeMessage, options => options.Ignore())
               .ForMember(model => model.AllowReSendingOfActivationMessage, options => options.Ignore());

            CreateMap<CustomerModel, Customer>()
                .ForMember(entity => entity.CustomerGuid, options => options.Ignore())
                .ForMember(entity => entity.CreatedOnTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.LastActivityTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.EmailToRevalidate, options => options.Ignore())
                .ForMember(entity => entity.HasShoppingCartItems, options => options.Ignore())
                .ForMember(entity => entity.RequireChangingPwd, options => options.Ignore())
                .ForMember(entity => entity.FailedLoginAttempts, options => options.Ignore())
                .ForMember(entity => entity.CannotLoginUntilDateUtc, options => options.Ignore())
                .ForMember(entity => entity.IsDeleted, options => options.Ignore())
                .ForMember(entity => entity.LastLoginTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.RegisteredInStoreId, options => options.Ignore());
        }

        protected virtual void CreateSystemModuleMaps()
        {
            CreateMap<SystemModule, SystemModuleModel>()
                .ForMember(model => model.LimitedStoreIds, options => options.Ignore())
                .ForMember(model => model.ModuleAssignedButtonIds, options => options.MapFrom(entity => entity.ModuleButtonIds))
                .ForMember(model => model.ModuleAuthorizedButtonIds, options => options.Ignore());

            CreateMap<SystemModuleModel, SystemModule>()
                .ForMember(entity => entity.CreatedOnTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.UpdatedOnTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.LimitedToStores, options => options.Ignore())
                .ForMember(entity => entity.AssignedModuleButtonIds, options => options.Ignore())
                .ForMember(entity => entity.ModuleButtonIds, options => options.MapFrom(model => model.ModuleAssignedButtonIds));

            CreateMap<ModuleButton, ModuleButtonModel>();
            CreateMap<ModuleButtonModel, ModuleButtonModel>();
        }

        protected virtual void CreateSystemScheduleTaskMaps()
        {
            CreateMap<SystemScheduleTask, ScheduleTaskModel>()
                .ForMember(model => model.LastStartTime, options => options.Ignore())
                .ForMember(model => model.LastStopTime, options => options.Ignore())
                .ForMember(model => model.LastSuccessTime, options => options.Ignore());
            CreateMap<ScheduleTaskModel, SystemScheduleTask>()
                .ForMember(entity => entity.IsActive, options => options.Ignore())
                .ForMember(entity => entity.CreatedOnTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.UpdatedOnTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.LastStartTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.LastStopTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.LastSuccessTimeUtc, options => options.Ignore());
                
        }

        protected virtual void CreateQueuedEmailMaps()
        {
            CreateMap<QueuedEmail, QueuedEmailModel>()
                .ForMember(model => model.CustomerId, options => options.Ignore())
                .ForMember(model => model.DontSendBeforeDate, options => options.Ignore())
                .ForMember(model => model.SentOnTime, options => options.Ignore());
            CreateMap<QueuedEmailModel, QueuedEmail>()
                .ForMember(entity => entity.DontSendBeforeDateUtc, options => options.Ignore())
                .ForMember(entity => entity.SentOnTimeUtc, options => options.Ignore());
        }

        /// <summary>
        /// Create NaviMenu maps 
        /// </summary>
        protected virtual void CreateNaviMenuMaps()
        {
            CreateMap<NaviMenu, NaviMenuEditModel>()
                .ForMember(model => model.SelectedTemplateIds, options => options.Ignore())
                .ForMember(model => model.AvailableLayoutTemplates, options => options.Ignore())
                .ForMember(model => model.AvailableParentMenus, options => options.Ignore())
                .ForMember(model => model.AvailableLanguages, options => options.Ignore())
                .ForMember(model => model.MenuGroup, options => options.Ignore())
                .ForMember(model => model.IconImageModel, options => options.Ignore())
                .ForMember(model => model.CoverImageModel, options => options.Ignore())
                .ForMember(model => model.NaviMenuBreadcrumb, options => options.Ignore());
            CreateMap<NaviMenuEditModel, NaviMenu>()
                .ForMember(entity => entity.MenuGroupId, options => options.Ignore())
                .ForMember(entity => entity.IconImageId, options => options.MapFrom(model => model.IconImageModel.Id))
                .ForMember(entity => entity.IconImageUrl, options => options.MapFrom(model => model.IconImageModel.ImageUrl))
                .ForMember(entity => entity.CoverImageId, options => options.MapFrom(model => model.CoverImageModel.Id))
                .ForMember(entity => entity.CoverImageUrl, options => options.MapFrom(model => model.CoverImageModel.ImageUrl))
                .ForMember(entity => entity.CreatedOnTimeUtc, options => options.Ignore())
                .ForMember(entity => entity.UpdatedOnTimeUtc, options => options.Ignore());

            //CreateMap<CategoryTemplate, CategoryTemplateModel>();
            //CreateMap<CategoryTemplateModel, CategoryTemplate>();
        }

        #endregion

        public int Order => 0;
    }
}
